package pl.poznan.put.cs.idss.viamdp.core.structures;

import java.text.DecimalFormat;

/**
 * Pole, które można odwiedzić. Nie wywołuje zakończenia.
 * 
 * @author Kornel Lewandowski
 * 
 */
public class AvailableField extends AbstractField implements IField {

	public static final double LITTLE_VALUE = -100.00000931231;

	private long currentIteration = 0;

	public AvailableField(int positionX, int positionY, Map worldMap) {
		super(positionX, positionY, worldMap);
	}

	public double calculateCurrentReward() {

		currentIteration = worldMap.getIteration();

		// System.out.println("Field: \t" + positionX + "\t" + positionY);
		// System.out.println("TOP: \t" + checkMoveTop());
		// System.out.println("BOTTOM: \t" + checkMoveBottom());
		// System.out.println("LEFT: \t" + checkMoveLeft());
		// System.out.println("RIGHT: \t" + checkMoveRight());

		// TODO poprawić coś, żeby przy dodadniej nagrodzie opłacało się
		// wchodzić na forbidden

		double bestMoveHorizontal = Math.max(checkMoveTop(), checkMoveBottom());
		double bestMoveVertical = Math.max(checkMoveLeft(), checkMoveRight());

		double bestMove = Math.max(bestMoveHorizontal, bestMoveVertical);

		double result = (worldMap.getDiscountValue() * bestMove);

		if (result != ForbiddenField.FORBIDDEN_VALUE
				&& result != (getLastReward() / worldMap.getDiscountValue())) {
			result += worldMap.getMoveReward();

		} else {
			System.out.println("for FIELD \t" + positionX + " \t" + positionY
					+ "\t is MOVE to FORBIDDEN");
			result = getLastReward() + worldMap.getMoveReward();
		}

		setRewardValue(result);

		return result;
	}

	public void setRewardValue(double reward) {
		history.add(new Double(reward));
	}

	public double getReward(long iteration) {
		if (history.size() > (int) iteration) {
			return history.get((int) iteration);
		} else {
			return LITTLE_VALUE;
		}
	}

	public double getLastReward() {
		return history.get(history.size() - 1);
	}

	public boolean checkIfRewardChange() {
		if (history.size() > 2
				&& (Math.abs(history.get(history.size() - 1)
						- history.get(history.size() - 2))) < worldMap
							.getIndifferenceThreshold()) {
			return false;
		} else {
			return true;
		}
	}

	/**
	 * Sprawdza możliwą nagrodę dla ruchu w górę.
	 * 
	 * @return wartość nagrody.
	 */
	private double checkMoveTop() {

		double result = 0.0;

		result += getTopNeighbourReward(currentIteration - 1)
				* worldMap.getCorrectMoveProbability();
		result += getBottomNeighbourReward(currentIteration - 1)
				* worldMap.getGoBackMoveProbability();
		result += getLeftNeighbourReward(currentIteration - 1)
				* worldMap.getTurnLeftMoveProbability();
		result += getBottomNeighbourReward(currentIteration - 1)
				* worldMap.getTurnRightMoveProbability();

		if (getTopNeighbourReward(currentIteration - 1) == ForbiddenField.FORBIDDEN_VALUE) {
			result = getLastReward();// + worldMap.getMoveReward();
			result /= worldMap.getDiscountValue();
		}

		// result += worldMap.getMoveReward();

		return result;

	}

	/**
	 * Sprawdza możliwą nagrodę dla ruchu w dół.
	 * 
	 * @return wartość nagrody.
	 */
	private double checkMoveBottom() {
		double result = 0.0;

		result += getBottomNeighbourReward(currentIteration - 1)
				* worldMap.getCorrectMoveProbability();
		result += getTopNeighbourReward(currentIteration - 1)
				* worldMap.getGoBackMoveProbability();
		result += getRightNeighbourReward(currentIteration - 1)
				* worldMap.getTurnLeftMoveProbability();
		result += getLeftNeighbourReward(currentIteration - 1)
				* worldMap.getTurnRightMoveProbability();

		if (getBottomNeighbourReward(currentIteration - 1) == ForbiddenField.FORBIDDEN_VALUE) {
			result = getLastReward();// + worldMap.getMoveReward();
			result /= worldMap.getDiscountValue();
		}

		// result += worldMap.getMoveReward();

		return result;

	}

	/**
	 * Sprawdza możliwą nagrodę dla ruchu w lewo.
	 * 
	 * @return wartość nagrody.
	 */
	private double checkMoveLeft() {
		double result = 0.0;

		result += getLeftNeighbourReward(currentIteration - 1)
				* worldMap.getCorrectMoveProbability();
		result += getRightNeighbourReward(currentIteration - 1)
				* worldMap.getGoBackMoveProbability();
		result += getBottomNeighbourReward(currentIteration - 1)
				* worldMap.getTurnLeftMoveProbability();
		result += getTopNeighbourReward(currentIteration - 1)
				* worldMap.getTurnRightMoveProbability();

		if (getLeftNeighbourReward(currentIteration - 1) == ForbiddenField.FORBIDDEN_VALUE) {
			result = getLastReward();// + worldMap.getMoveReward();
			result /= worldMap.getDiscountValue();
		}

		// result += worldMap.getMoveReward();

		return result;

	}

	/**
	 * Sprawdza możliwą nagrodę dla ruchu w right.
	 * 
	 * @return wartość nagrody.
	 */
	private double checkMoveRight() {

		double result = 0.0;

		result += getRightNeighbourReward(currentIteration - 1)
				* worldMap.getCorrectMoveProbability();
		result += getLeftNeighbourReward(currentIteration - 1)
				* worldMap.getGoBackMoveProbability();
		result += getTopNeighbourReward(currentIteration - 1)
				* worldMap.getTurnLeftMoveProbability();
		result += getBottomNeighbourReward(currentIteration - 1)
				* worldMap.getTurnRightMoveProbability();

		if (getRightNeighbourReward(currentIteration - 1) == ForbiddenField.FORBIDDEN_VALUE) {
			result = getLastReward();// + worldMap.getMoveReward();
			result /= worldMap.getDiscountValue();
		}

		// result += worldMap.getMoveReward();

		return result;

	}

	@Override
	public String toString() {
		DecimalFormat df = new DecimalFormat("##.###");
		return df.format((getLastReward()));
	}

}
